package com.voip.Invite;

import javax.media.*;
import javax.media.rtp.InvalidSessionAddressException;
import javax.media.rtp.SessionAddress;
import javax.sdp.*;
import javax.sip.*;
import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.header.*;
import javax.sip.message.Message;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Vector;

/**
 * Created by RXJ on 2018/1/25.
 */
public class SipInboundCall extends SipCall implements RequestListener, ResponseListener {
    int localMediaPort;

    String remoteHost = null;
    SipFactory sipFactory;

    public SipInboundCall() {
        localMediaPort = -1;

        sipHandler = SipHandler.getInstance("127.0.0.1", 5060);
        sipFactory = SipFactory.getInstance();

        try {
            DatagramSocket socket = new DatagramSocket();
            localMediaPort = socket.getLocalPort();
            socket.close();
            initRTP(localMediaPort);
        } catch (Exception e1) {
            System.out.println(e1);
        }


        sipHandler.addRequestListener(this);
        sipHandler.addResponseListener(this);



    }

    public void init(String hostName, int port) {
        sipHandler.setRemoteHost(hostName);
        sipHandler.setRemotePort(port);
        sipHandler.init();
    }

    public void handleRequest(RequestEvent requestEvent) {
        Request request = requestEvent.getRequest();
        String method = ((CSeqHeader) request.getHeader(CSeqHeader.NAME))
                .getMethod();
        if (method.equals(Request.INVITE)) {
            FromHeader fromHeader =  (FromHeader)request.getHeader(FromHeader.NAME);
            recipient = fromHeader.getAddress().toString();
            remoteHost = ((SipURI)fromHeader.getAddress().getURI()).getHost();
            sipHandler.setRemoteHost(remoteHost);
            sendInviteReply(requestEvent);
        } else if (method.equals (Request.BYE)) {
            hangup();
        }
    }

    public void handleResponse(ResponseEvent responseEvent) {
        // TODO Auto-generated method stub

    }

    /**
     * @param requestEvent
     */
    private void sendInviteReply(RequestEvent requestEvent) {
        int port = 8000;

        try {
            DatagramSocket socket = new DatagramSocket();
            port = socket.getLocalPort();
            socket.close();
        } catch (SocketException e1) {
            System.out.println(e1);
        }

        try {
            Request request = requestEvent.getRequest();
            ServerTransaction st = requestEvent.getServerTransaction();

            // Send the 180 Trying
            Response response = sipFactory.createMessageFactory()
                    .createResponse(180, request);
            ToHeader toHeader = (ToHeader) response.getHeader(ToHeader.NAME);
            toHeader.setTag("4321"); // Application is supposed to set.
            response.addHeader(toHeader);

            Address address = sipFactory.createAddressFactory().createAddress(
                    "Reliable Response <sip:" + sipHandler.getLocalHost() + ":"
                            + sipHandler.getLocalPort() + ">");

            ContactHeader contactHeader = sipFactory.createHeaderFactory()
                    .createContactHeader(address);
            response.addHeader(contactHeader);

            if (st == null) {
                st = sipHandler.getSipProvider().getNewServerTransaction(
                        request);
            }

            st.sendResponse(response);

            // Send the 200 OK Invite
            response = sipFactory.createMessageFactory().createResponse(200,
                    request);
            response.addHeader(toHeader);
            response.addHeader(contactHeader);

            ContentTypeHeader contentTypeHeader = null;
            //content type should be application/sdp (not applications)
            //reported by Oleg Shevchenko (Miratech)
            contentTypeHeader = sipFactory.createHeaderFactory()
                    .createContentTypeHeader("application", "sdp");

            String sdpContent = "v=0\n" + "o=drig 0 0 IN IP4 "
                    + sipHandler.getLocalHost() + "\n" + "s=SIP Call\n"
                    + "c=IN IP4 " + sipHandler.getLocalHost() + "\n"
                    + "t=0 0\n" + "m=audio " + localMediaPort
                    + " RTP/AVP 4 3 0 5 6 8 15 18\n" + "a=sendrecv\n"
                    + "a=rtpmap:0 PCMU/8000\n";

            response.setContent(sdpContent, contentTypeHeader);


            st.sendResponse(response);

            startConversation(request, st);
            synchronized (this) {
                this.notifyAll();
            }
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    void startConversation(Message response,
                           Transaction clientTransaction) throws SipException,
            SdpParseException, SdpException, IOException,
            NoDataSourceException, NoProcessorException, InterruptedException,
            NotConfiguredError, NotRealizedError, NoDataSinkException,
            InvalidSessionAddressException, UnknownHostException {

        System.out.println("Starting conversation");

        String sdpData = new String(response.getRawContent());
        SdpFactory sdpFactory = SdpFactory.getInstance();
        SessionDescription sessionDescription = sdpFactory
                .createSessionDescription(sdpData);
        Vector mediaDescriptions = sessionDescription
                .getMediaDescriptions(true);
        for (int mdNum = 0; mdNum < mediaDescriptions.size(); mdNum++) {
            MediaDescription mediaDescription = (MediaDescription) mediaDescriptions
                    .elementAt(mdNum);
            Media media = mediaDescription.getMedia();
            String proto = media.getProtocol();
            String type = media.getMediaType();
            int port = media.getMediaPort();

            Vector formats = media.getMediaFormats(true);

            if (formats.size() < 1) {

            }
            int sdpFormat = SdpConstants.PCMU;
            try {
                sdpFormat = Integer.parseInt((String) formats.elementAt(0));
            } catch (NumberFormatException nfExc) {
                nfExc.printStackTrace();
            }

            startReceiver(localMediaPort);
            transmitter = new RtpTransmitter(remoteHost, port, sdpFormat);
        }
    }

    private void startReceiver(int port) throws InvalidSessionAddressException,
            IOException, UnknownHostException {


        SessionAddress remoteAddress = new SessionAddress(InetAddress
                .getByName(sipHandler.getRemoteHost()), port);
        rtpManager.addTarget(remoteAddress);
    }


    public static void main(String[] args) throws Exception {


        SipInboundCall in = new SipInboundCall();
//  in.setRegistrarHost("sys1a.TelecomMatters.net");
//  in.setRegistrarPort(5060);
//  in.setRegistrarDomain("asterisk");
//  in.setUsername("daverudder");
//  in.setPassword("3035421990");
//  in.init("sys1a.TelecomMatters.net", 5060);
        in.init ("10.10.10.5", 5060);
    }
}
